#include "dib.h"
#include "resource.h"
#include "operations.h"

#include "dot_operations.h"
#include "rebuilding_operations.h"
#include "sizing_operations.h"
#include "file_operations.h"

bool Task::createDestination( unsigned int width, unsigned int height )
{
	DIB::Format fmt = _originalImage->format();

	//Create a deep copy of the format, to prevent altering the format
	//of the original image.
	fmt.makeSelfContained();

	fmt->bmiHeader.biWidth = width;
	fmt->bmiHeader.biHeight = height;

	//Create the destination image.
	_destinationImage = new DIB();
	_destinationImage->setFormat( fmt );
	if( false == _destinationImage->create() )
	{
		delete _destinationImage;
		return false;
	}
	return true;
}

bool Task::createPaddedImage( unsigned int width, unsigned int height )
{
	DIB::Format fmt =  _paddedImage->format();

	//Create a deep copy of the format, to prevent altering the format
	//of the original image.
	fmt.makeSelfContained();

	fmt->bmiHeader.biWidth = width;
	fmt->bmiHeader.biHeight = height;

	//Create the destination image.
	_paddedImage = new DIB();
	_paddedImage->setFormat( fmt );
	if( false == _paddedImage->create() )
	{
		delete _paddedImage;
		return false;
	}
	return true;
}

bool performOperation( Task *task, WORD id )
{
	//An operation is ready to process.
	if( task->_operationType == Task::DOT_OPERATION )
	{
		//In a dot operation, only the original image is used.
		DIB *dib = task->_originalImage;
		Image image = dib->getImage();

		bool success = false;
		switch( id )
		{
		case ID_COLORMODE_GRAYSCALE:
			success = grayscale( image, task->_data );
			break;
		case ID_COLORMODE_MONOTONE:
			success = monotone( image, task->_data );
			break;
		case ID_COLORMODE_YCBCR:
			success = yCbCr( image, task->_data );
			break;
		case ID_IMAGE_RGBLEVELS:
			success = rgbLevels( image, task->_data );
			break;
		case ID_IMAGE_CONTRAST:
			success = contrast( image, task->_data );
			break;
		case ID_IMAGE_INVERT:
			success = invert( image, task->_data );
			break;
		case ID_IMAGE_TRESHOLD:
			success = threshold( image, task->_data );
			break;
		case ID_MATHMATICAL_EXPONENT:
			success = exponent( image, task->_data );
			break;
		case ID_MATHMATICAL_LOGARITHM:
			success = logarithm( image, task->_data );
			break;
		case ID_MATHMATICAL_NATURALLOGARITHM:
			success = naturalLogarithm( image, task->_data );
			break;
		default:
			break;
		}
		return success;
	}
	else if( task->_operationType == Task::REBUILDING_OPERATION )
	{
		//In a rebuilding operation, the destination image contains the result.
		//The destination image is initialized but empty.
		DIB *dibSource = task->_originalImage;
		DIB *dibResult = task->_destinationImage;
		Image imageSource = dibSource->getImage();
		Image imageResult = dibResult->getImage();

		bool success = false;
		switch( id )
		{
		case ID_FLIP_HORIZONTAL:
			success = flipHorizontal( imageSource, imageResult, task->_data );
			break;
		case ID_FLIP_VERTICAL:
			success = flipVertical( imageSource, imageResult, task->_data );
			break;
		case ID_FILTER_MEDIAN:
			success = median( imageSource, imageResult, task );
			break;
		case ID_FILTER_AVERAGE:
			success = average( imageSource, imageResult, task );
			break;
		case ID_FILTER_EMBOSS:
			success = emboss( imageSource, imageResult, task->_data );
			break;
		case ID_FILTER_GAUSS:
			success = gauss( imageSource, imageResult, task );
			break;
		case ID_SOBEL_HORIZONTAL:
			success = sobelHorizontal( imageSource, imageResult, task );
			break;
		case ID_SOBEL_VERTICAL:
			success = sobelVertical( imageSource, imageResult, task );
			break;
		case ID_FILTER_LAPLACE:
			success = laplace( imageSource, imageResult, task );
			break;
		case ID_MATHMATICAL_DISCRETECOSINETRANSFORM:
			success = discreteCosineTransform( imageSource, imageResult, task->_data );
			break;
		default:
			break;
		}
		return success;
	}
	else if( task->_operationType == Task::SIZING_OPERATION )
	{
		//In a sizing operation, the destination image contains the result. The
		//result image is initialized at the right size (it is still empty).
		DIB *dibSource = task->_originalImage;
		DIB *dibResult = task->_destinationImage;
		Image imageSource = dibSource->getImage();
		Image imageResult = dibResult->getImage();

		if( dibResult == NULL )
		{
			//Setup failed to create a DIB instance.
			return false;
		}

		bool success = false;
		switch( id )
		{
		case ID_IMAGE_ROTATE:
			success = rotate( imageSource, imageResult, task->_data );
			break;
		case ID_IMAGE_RESIZE:
			success = resize( imageSource, imageResult, task->_data );
			break;
		default:
			break;
		}
		return success;
	}
	else if( task->_operationType == Task::FILE_OPERATION )
	{
		//In a file operation, the original image contains the newly opened file
		//and the destination contains the original, which must be altered to
		//become the result.
		DIB *dibSource = task->_originalImage;
		DIB *dibResult = task->_destinationImage;
		Image imageSource = dibSource->getImage();
		Image imageResult = dibResult->getImage();

		if( dibResult == NULL )
		{
			//Setup failed to create a DIB instance.
			return false;
		}

		bool success = false;
		switch( id )
		{
		case ID_MATHMATICAL_ADD:
			success = add( imageSource, imageResult, task->_data );
			break;
		case ID_MATHMATICAL_MULTIPLY:
			success = multiply( imageSource, imageResult, task->_data );
			break;
		case ID_MATHMATICAL_SUBTRACT:
			success = subtract( imageSource, imageResult, task->_data );
			break;
		default:
			break;
		}
		return success;
	}
	return false; //Unknown operation type.
}
